import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { IsNull, Like, Repository } from 'typeorm';
import date_diff from '../atom/date-diff'
import { Changelog } from './changelog.entity';
import { IAdd, ICreatQuestion, IEdit, IProp, ISearch } from './docs.dto'
import { Docs } from './docs.entity';
import { Props } from './props.entity';
import { Question } from './question.entity';

@Injectable()
export class DocsService {
	constructor(
		@InjectRepository(Docs)
		private readonly docsRepository: Repository<Docs>,
		@InjectRepository(Props)
		private readonly propsRepository: Repository<Props>,
		@InjectRepository(Changelog)
		private readonly changelogRepository: Repository<Changelog>,
		@InjectRepository(Question)
		private readonly questionRepository: Repository<Question>

	) { }

	// 查询所有文档，按照修改时间逆序
	async list(spaceid: string, type: string) {
		const where = {
			spaceid,
			type
		}
		const res = await this.docsRepository.find({
			select: ['project_id', 'doc_id', 'doc_parent_id', 'doc_title', 'edit_time', 'editer', 'status', 'partners', 'creater'],
			where,
			order: {
				edit_time: 'DESC'
			}
		});
		const data = this.return_data(res)
		const doc_ids = data.map((i) => {
			return { doc_id: i.doc_id }
		})
		const questions = await this.questionRepository.find({
			select: ['doc_id', 'state'],
			where: doc_ids
		})
		const M = questions.reduce((p, c) => {
			const i = p.get(c.doc_id)
			if (!i) {
				p.set(c.doc_id, [c])
			} else {
				i.push(c)
			}
			return p
		}, new Map()) as Map<string, Question[]>
		return data.map((j) => {
			return {
				...j,
				has_unsolved: M.get(j.doc_id) ? M.get(j.doc_id).some((m) => {
					return m.state === 0
				}) : false,
				has_unconfirmed: M.get(j.doc_id) ? M.get(j.doc_id).some((m) => {
					return m.state === 2
				}) : false
			}
		})
	}

	return_data(arr: Docs[]) {
		return arr.filter((item) => {
			return item.status !== null;
		}).map((i) => {
			const levels = this.get_levels(i.doc_parent_id, arr, []).reverse()
			return {
				...i, edit_time_display: date_diff(i.edit_time),
				levels
			}
		})
	}

	get_levels(doc_parent_id: string, data: Docs[], results: Docs[]): Docs[] {
		const res = data.find((i) => {
			return i.doc_id === doc_parent_id;
		})
		if (res) {
			results.push(res)
			return this.get_levels(res.doc_parent_id, data, results)
		} else {
			return results
		}
	}

	/**
	 * 新增文章
	 * @param body IAdd
	 */
	async add(body: IAdd) {
		// project_id, spaceid, type, doc_parent_id, doc_title, tables, params, returns
		const now = new Date().getTime()
		const res = await this.docsRepository.save({
			project_id: body.project_id,
			doc_parent_id: body.doc_parent_id,
			doc_title: body.doc_title,
			message_type: body.message_type,
			editer: body.editer,
			creater: body.editer,
			spaceid: body.spaceid,
			type: body.type,
			tables: body.tables,
			params: body.params,
			returns: body.returns,
			status: 1,
			edit_time: now,
			creat_time: now
		});
		const returns_prop = body.returns_prop.map((i) => {
			return { ...i, doc_id: res.doc_id, optional: JSON.stringify(i.optional), class: 'return' }
		})
		const params_prop = body.params_prop.map((i) => {
			return { ...i, doc_id: res.doc_id, optional: JSON.stringify(i.optional), class: 'param' }
		})
		await this.propsRepository.delete({
			doc_id: res.doc_id
		})
		await this.propsRepository.save(params_prop.concat(returns_prop))
		await this.changelogRepository.save({
			doc_id: res.doc_id,
			editor: body.editer,
			message: '创建服务',
			version: now,
			edit_time: now
		})
		return {
			code: 1,
			msg: 'success'
		}
	}

	async add_classify(project_id, spaceid, type, doc_parent_id, doc_title, editer) {
		const now = new Date().getTime()
		await this.docsRepository.save({
			project_id,
			doc_parent_id,
			doc_title,
			editer,
			creater: editer,
			spaceid,
			type,
			creat_time: now,
			edit_time: now,
			status: null
		});
		return {
			code: 1,
			msg: 'success'
		}
	}

	/**
	 * 查询。头部搜索按钮和左侧树点击查看详情
	 * @param spaceid
	 * @param type
	 * @param doc_id
	 * @param doc_title
	 */
	async search(spaceid: string, type: string, doc_id: string, doc_title: string) {
		const where = (() => {
			if (doc_id) {
				return {
					spaceid, type,
					doc_parent_id: doc_id
				} as ISearch;
			} else if (doc_title) {
				return [{
					spaceid, type,
					doc_title: Like(`%${doc_title}%`)
				}, {
					spaceid, type,
					message_type: Like(`%${doc_title}%`)
				}]
			} else {
				return {}
			}
		})()

		const res = await this.docsRepository.find({
			select: ['doc_id'],
			where,
			order: {
				edit_time: 'DESC'
			}
		});
		const doc_ids = res.map((item) => {
			return item.doc_id
		})
		const all = await this.list(spaceid, type)
		return all.filter((i) => {
			return doc_ids.includes(i.doc_id)
		})
	}

	/**
	 * 查询文档分类
	 * @param spaceid
	 * @param type
	 */
	classify(spaceid, type) {
		return this.docsRepository.find({
			select: ['project_id', 'doc_id', 'doc_parent_id', 'doc_title', 'edit_time', 'editer', 'status'],
			where: {
				spaceid,
				type,
				status: IsNull()
			}
		});
	}

	/**
	 * 文档详情
	 * @param doc_id string
	 */
	async find(doc_id: string) {
		const res = await this.docsRepository.findOne({
			doc_id
		});
		if (res) {
			const changelog = await this.changelogRepository.find({
				doc_id
			}) as { doc_id: string, edit_time: number }[]
			const question = await this.questionRepository.find({
				doc_id
			}) as { doc_id: string, edit_time: number }[]
			const logs = changelog.concat(question).map((i) => {
				return { ...i, edit_time: Number(i.edit_time), edit_time_display: date_diff(i.edit_time) }
			}).sort((p, c) => {
				return c.edit_time - p.edit_time
			})

			const ret = await this.propsRepository.find({
				doc_id
			});
			const returns = []
			const params = []
			ret.forEach((item) => {
				item.optional = JSON.parse(item.optional)
				if (item.class === 'return') {
					returns.push(item)
				} else {
					params.push(item)
				}
			})
			return {
				data: {
					...res,
					edit_time_display: date_diff(res.edit_time)
				},
				returns,
				params,
				logs,
				code: 1,
				msg: 'success'
			}
		} else {
			return {
				data: {},
				code: 0,
				msg: 'no data'
			}
		}
	}

	/**
	 * 修改文档
	 * @param body IEdit
	 */
	async edit(body: IEdit) {
		const res = await this.docsRepository.findOne({
			doc_id: body.doc_id
		});
		if (res) {
			const now = new Date().getTime()
			const obj = { doc_title: body.doc_title, tables: body.tables, params: body.params, returns: body.returns, edit_time: now, editer: body.editer, partners: res.partners }
			// 把编辑者加入相关者内
			const partners = res.partners
			if (!partners || partners.indexOf(body.editer) === -1) {
				const p = partners ? JSON.parse(partners) : []
				p.push(body.editer)
				obj.partners = JSON.stringify(p)
			}
			await this.docsRepository.update({
				doc_id: body.doc_id
			}, obj)
			await this.changelogRepository.save({
				doc_id: body.doc_id,
				editor: body.editer,
				message: body.message,
				version: now,
				edit_time: now
			})
			const returns_prop = body.returns_prop.map((i) => {
				return { ...i, doc_id: body.doc_id, optional: JSON.stringify(i.optional), class: 'return' }
			})
			const params_prop = body.params_prop.map((i) => {
				return { ...i, doc_id: body.doc_id, optional: JSON.stringify(i.optional), class: 'param' }
			})
			await this.propsRepository.delete({
				doc_id: body.doc_id
			})
			await this.propsRepository.save(params_prop.concat(returns_prop))

			return {
				code: 1,
				msg: 'success'
			}
		}
		else {
			return res
		}
	}

	/**
	 * 删除文档
	 * @param doc_id
	 */
	async del_doc(doc_id: string) {
		await this.docsRepository.delete({
			doc_id
		})
		await this.propsRepository.delete({
			doc_id
		})
		await this.questionRepository.delete({
			doc_id
		})
		return this.changelogRepository.delete({
			doc_id
		})
	}

	/**
	 * 删除分类
	 * @param doc_id
	 */
	async del_classify(doc_id: string) {
		const res = await this.docsRepository.find({
			select: ['doc_id'],
			where: {
				doc_parent_id: doc_id
			}
		}) as { doc_id: string; }[]
		res.push({ doc_id })
		const ps = res.map((i) => {
			return this.del_doc(i.doc_id)
		})
		return await Promise.all(ps)
	}

	async add_question(body: ICreatQuestion) {
		await this.questionRepository.save({
			state: 0,
			doc_id: body.doc_id,
			message: body.message,
			editor: body.editor,
			params: body.params,
			edit_time: new Date().getTime()
		})
		return {
			code: 1,
			msg: 'success'
		}
	}

	async attention(doc_id, user) {
		const res = await this.docsRepository.findOne({
			doc_id
		})
		if (!res.partners || res.partners.indexOf(user) === -1) {
			const partners = res.partners ? JSON.parse(res.partners) : []
			partners.push(user)
			await this.docsRepository.update({
				doc_id
			}, {
				partners: JSON.stringify(partners)
			})
			return {
				code: 1,
				message: 'success'
			}
		} else {
			return {
				code: 1,
				message: '已经关注'
			}
		}
	}

	async change_state(question_id, state, user) {
		const obj = {
			state
		} as { state: number; confirmor?: string, confirm_time?: number }
		if (state === 2) {
			obj.confirmor = user
			obj.confirm_time = new Date().getTime()
		}
		await this.questionRepository.update({
			question_id
		}, obj)
		return {
			code: 1,
			message: 'success'
		}
	}
}
